/* Definitions for init operations.

   This file is part of khipu.

   khipu is free software: you can redistribute it and/or modify
   it under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */

#include <cstdio>
#include <cstdlib>
#include "initop.hpp"
#include "memory.hpp"

KP_DECLS_BEGIN

init_op_list& init_op_list::global_ops ()
{
  static init_op_list lst;
  return (lst);
}

bool init_op_list::call (interpreter *interp)
{
  for (auto it = this->ops.iterator (&init_op::link); it.valid (); ++it)
    {
      int ret = it->call (interp);
      if (ret == init_op::result_circular)
        {
          fprintf (stderr, "Circular dependency detected "
            "in call to %s\n", it->name);
          return (false);
        }
      else if (ret == init_op::result_failed)
        {
          fprintf (stderr, "Failed to initialize %s\n", it->name);
          return (false);
        }
    }

  return (true);
}

interpreter *main_interp;

bool khipu_init (char *base, uint32_t size)
{
  static interpreter ip_main;
  main_interp = &ip_main;

  if (!memory_init ())
    {
      fputs ("failed to initialize memory subsystem", stderr);
      return (false);
    }

  if (!main_interp->init (base, size))
    return (false);
  else if (!init_op_list::global_ops().call (main_interp))
    {
      fputs ("init ops failed: ", stderr);
      fputs (init_op_list::global_ops().errmsg, stderr);
      return (false);
    }
  else if (atexit (memory_exit) != 0)
    {
      fputs ("could not install atexit handler", stderr);
      return (false);
    }

  gc_enable ();
  return (true);
}

KP_DECLS_END
